package inglar.autotc.server.daemon;

import inglar.autotc.server.ConfigFile;
import inglar.autotc.server.Database;
import inglar.autotc.server.Host;
import inglar.autotc.shared.Values;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Iterator;
import java.util.Vector;

import org.mortbay.jetty.Server;
import org.mortbay.jetty.webapp.WebAppContext;

/**
 * This is used to wrap the shell command for using jsvc, along with other features
 * @author Lee
 */
public class Loader {
	
	private static final long PIDFILE_WAIT = 500;

	private static String javaHome = "";
	
	private static String dbhost = "localhost";
	private static String dbport = "3306";
	private static String dbuser = "root";
	private static String dbpass = "password";
	
	private static ConfigFile cfg = null;
	private static String errfile = null;
	private static String outfile = null;
	private static String pidfile = null; 
	private static String jarfile = null;
	private static String entrypt = null;
	
	public static void main(String[] args) {
		
		// must have JAVA_HOME environment variable set
		javaHome = Host.getJavaHome();
		
		// get values
		cfg = new ConfigFile("config.cfg");
		errfile = cfg.getValue("ERRFILE", "autotc-error.log");
		outfile = cfg.getValue("OUTFILE", "autotc.log");
		pidfile = cfg.getValue("PIDFILE", "autotc.jsvc.pid"); 
		jarfile = cfg.getValue("JARFILE", "autotc.jar");
		entrypt = Daemon.class.getName();
		dbhost = cfg.getValue("DBHOST", "localhost");
		dbport = cfg.getValue("DBPORT", "3306");
		dbuser = cfg.getValue("DBUSER", "root");
		dbpass = cfg.getValue("DBPASS", "password");
		
		if(args.length == 0) {
			
			System.out.println(Values.DAEMON_LOADER_BADARGS);
			
		} else if(args[0].equals("-version")) {
			
			System.out.println("v " + Values.APP_VERSION + "");
			
		} else if(args[0].equals("-start")) { // start the daemon
			
			try {
				String r = "";
				
				File file = new File(pidfile);
				if(file.exists() && file.canRead()) {
					r = Host.exec("cat " + pidfile);
					Host.fatal("The daemon is still running. PID: " + r + " (" + pidfile + ")");
				}
				
				// remove log files
				Host.exec("sudo rm -f " + errfile + "; sudo rm -f " + outfile);
				
				// execute jsvc
				r = Host.exec(
						"sudo jsvc" +
						" -errfile " + errfile +
						" -outfile " + outfile +
						" -pidfile " + pidfile +
						" -home " + javaHome +
						" -cp " +  jarfile +
						" -D" + Values.ENVNAME_JAVA_DAEMON_DBHOST + "=" + dbhost +
						" -D" + Values.ENVNAME_JAVA_DAEMON_DBPORT + "=" + dbport +
						" -D" + Values.ENVNAME_JAVA_DAEMON_DBUSER + "=" + dbuser +
						" -D" + Values.ENVNAME_JAVA_DAEMON_DBPASS + "=" + dbpass +
						" " + entrypt
						);
				if(!r.isEmpty()) {
					Host.fatal("Unexpected String object returned: '" + r + "'");
				}
				
				boolean hasStarted = false;
				for(int i = 0; i < 80; i++) {
					Thread.sleep(PIDFILE_WAIT);
					if(file.exists()) {
						hasStarted = true;
						break;
					}
					Host.out(".");
				}
				
				if(hasStarted) {
					Host.out("The daemon has started. Please see " + outfile + " and " + errfile + " for details.");
				} else {
					Host.out("The daemon did not start. Please see " + outfile + " and " + errfile + " for details.");
				}
			} catch (Throwable t) {
				Host.fatal(t);
			} 
		} else if(args[0].equals("-stop")) { // stop the daemon
			try {
				String r = Host.exec(
						"sudo jsvc" +
//						" -errfile " + cfg.getErrFile() +
//						" -outfile " + cfg.getOutFile() +
						" -pidfile " + pidfile +
						" -home " + javaHome +
//						" -cp " +  cfg.getAppJar() +
						" -stop" +
						" " + entrypt
						);
				if(!r.isEmpty()) {
					throw new Exception(r);
				}
			} catch (Throwable t) {
				Host.fatal(t);
			}
		} else if(args[0].equals("-test")) {
			
			test();
			
		} else if(args[0].equals("-w")) {
			
			webappControl(args);
			
		} else if(args[0].equals("-u")) {
			
			userControl(args); // TODO 3 log out and log block?
			
		} else if(args[0].equals("-check")) { 
			
			checkInstallation();
			
		} else if(args[0].equals("-webapp")) { 
			
			Integer port = Integer.parseInt(cfg.getValue("WPORT", "19080"));
			try {
				port = Integer.parseInt(args[1]);
			} catch(Exception e) {
				
			}
			startServer(port);
			
			
		} else { 
			
			Host.fatal(Values.DAEMON_LOADER_BADARGS);
			
		}
	}

	/**
	 * Prints error messages if the installation of this application invalid; a newline otherwise.
	 */
	private static void checkInstallation() {
		// TODO 2 do jar check
		Host.out("");
	}

	static String removeAction(String id) {
		String retval = "";
		
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			
			String sql1 = "DELETE FROM `actions` WHERE `id` = '" + id + "'";
			
			if(stmt.executeUpdate(sql1) < 1) retval = "No rows updated.";
			
			stmt.close();
			con.close();
		} catch(Throwable t) {
			Host.out(Values.ErrorCode.D009badsetscript + "\nDetails: caught " + t.getClass() + "\nmsg: \"" + t.getMessage() + "\"");
			t.printStackTrace();
		}
		
		return retval;
	}

	/**
	 * 
	 * @param prio
	 * a nonnegative integer
	 * 
	 * @param detect
	 * 
	 * @param action
	 * set TEMPLATE_NAME
	 * 
	 * @return
	 */
	static String setAction(String prio, String detect, String action) {
		String retval = "";
		
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			
			String sql1 = "SELECT `id` FROM `actions` WHERE `prio` = '" + prio + "' AND `detect` = '" + detect + "' AND `action` = '" + action + "'";
			
			ResultSet rs1 = stmt.executeQuery(sql1);
			if(rs1.first()) {
				// line already exists, do nothing
			} else {
				String sql2 = "INSERT INTO `actions` (`prio`, `detect`, `action`) VALUES ('" + prio + "', '" + detect + "', '" + action + "')";
				if(stmt.executeUpdate(sql2) < 1) retval = "No rows updated.";
			}
			
			stmt.close();
			con.close();
		} catch(Throwable t) {
			Host.out(Values.ErrorCode.D009badsetscript + "\nDetails: caught " + t.getClass() + "\nmsg: \"" + t.getMessage() + "\"");
			t.printStackTrace();
		}
		
		return retval;
	}

	static String setTemplate(String device, String templatename, String script) {
		String retval = "";
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			
			String sql1 = "SELECT `id` FROM `templates` WHERE `name` = '"+ templatename + "'";
			ResultSet rs1 = stmt.executeQuery(sql1);
			if(rs1.first()) { // template exists 
				String sql2 = "UPDATE `templates` SET `script` = '" + script + "' WHERE `name` = '" + templatename + "'";
				if(stmt.executeUpdate(sql2) < 1) throw new RuntimeException("No row was updated.");
			} else { // create new template
				String sql3 = "INSERT INTO `templates` ( `id`, `name`, `device`, `script`) VALUES ( NULL, '" + templatename + "', '" + device + "', '" + script + "' )";
				if(stmt.executeUpdate(sql3) < 1) throw new RuntimeException("No row was added.");
			}
			rs1.close();
			
			stmt.close();
			con.close();
		} catch(Throwable t) {
			Host.out(Values.ErrorCode.D009badsetscript + "\nDetails: caught " + t.getClass() + "\nmsg: \"" + t.getMessage() + "\"");
			t.printStackTrace();
		}
		return retval;
	}

	static String getTemplateList(String device) {
		String retval = "";
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			String device_opt = "";
			if(device != null) device_opt = " WHERE `device` = '" + device + "'";
			
			String sql1 = "SELECT `id`, `name`, `device`, `script` FROM `templates`" + device_opt;
			ResultSet rs1 = stmt.executeQuery(sql1);
			if(rs1.first()) {
				do {
					String id = rs1.getString(1);
					String name = rs1.getString(2);
					String tdevice = rs1.getString(3);
					String script = rs1.getString(4);
					retval += id + "#" + name + "#" + tdevice + "#" + script + "\n";
				} while(rs1.next());
			}
			
			stmt.close();
			con.close();
		} catch(Throwable t) {
			Host.out(Values.ErrorCode.D009badsetscript + "\nDetails: caught " + t.getClass() + "\nmsg: \"" + t.getMessage() + "\"");
			t.printStackTrace();
		}
		return retval;
	}

	/**
	 * Sets a <i>tc</i> configuration script for a device.
	 * @param device device name
	 * @param settingid the setting id number; use <code>null</code> if the script is a custom one 
	 * @param userid userid of the user that sets the script 
	 * @param timestamp when it was created, may be any {@link String}
	 * @param script the script, may be any {@link String}
	 * @return empty {@link String} on success; an error message otherwise
	 */
	static String setScript(String device, String settingid, String userid, String timestamp, String script) {
		String retval = "";
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			
			String origcmd = "tc qdisc del dev " + device + " root";
			
			boolean notSaved = true;
			
			// get the previous working command
			String sql = "SELECT `script` FROM `devices` WHERE `device` = '" + device + "'";
			ResultSet rs1 = stmt.executeQuery(sql);
			if(rs1.first()) {
				String s = rs1.getString(1).trim();
				if(!s.isEmpty()) origcmd = s;
				notSaved = false;
			}
			
			// TODO 1 set userhook.action = mysql "NULL"
			
			// delete previous qdisc first
			try {
				Host.exec("sudo " + "tc qdisc del dev " + device + " root");
			} catch (Throwable caught) {
				
			}
			
			// run each of the commands
			String[] cmd = script.trim().split(";");
			for(int i = 0; i < cmd.length; i++) {
				String s = cmd[i].trim();
				if(s.isEmpty()) continue;
				String t = Host.exec("sudo " + s);
				if(t.isEmpty()) {
					
				} else {
					retval = "Error running line " + i +
							":\n\"" + s +
							"\"\n" + t;
					break;
				}
			}
			
			// if there is no error, save to mysql
			if(retval.isEmpty()) {
				String sql1 = "`devices` SET " +
						"   `settingid` =  " + settingid + ", " +
						"    `authorid` = '" + userid    + "', " +
						"   `timestamp` = '" + timestamp + "', " +
						"      `script` = '" + script    + "'";
				
				if(notSaved) {
					sql1 = "INSERT " + sql1 + ", `device` = '" + device + "'";
				} else {
					sql1 = "UPDATE " + sql1 + " WHERE `device` = '" + device + "'";
				}
				
				if(stmt.executeUpdate(sql1) < 1) {
					Host.exec(origcmd);
					throw new RuntimeException("No rows were updated.");
				}
			} else { // if there is an error, run the previous working command
				Host.exec(origcmd);
			}
			
			stmt.close();
			con.close();
		} catch(Throwable t) {
			Host.out(Values.ErrorCode.D009badsetscript + "\nDetails: caught " + t.getClass() + "\nmsg: \"" + t.getMessage() + "\"");
			t.printStackTrace();
		}
		return retval;
	}

	/**
	 * @param device
	 * @return <code>script#settingid#settingname#authorid#authorname#timestamp</code><br><code>null</code> on error
	 */
	static String getScript(String device) {
		String retval = null;
		
		String settingid = "";
		String settingname = "";
		String authorid = "";
		String authorname = "";
		String timestamp = "";
		String script = "";
		
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			
			String sql1 = "SELECT `script`, `settingid`, `authorid`, `timestamp` FROM `devices` WHERE `device`='" + device +"'";
			ResultSet rs1 = stmt.executeQuery(sql1);
			
			if(!rs1.first()) {
				return null;
			}
			script = rs1.getString(1);
			settingid = rs1.getString(2);
			authorid = rs1.getString(3);
			timestamp = rs1.getString(4);
			
			if(settingid != null) {
				String sql2 = "SELECT `name` FROM `templates` WHERE `id` = '" + settingid + "'";
				ResultSet rs2 = stmt.executeQuery(sql2);
				if(!rs2.first()) {
					return null;
				}
				settingname = rs2.getString(1);
				rs2.close();
			} else {
				settingname = "";
			}
			
			String sql3 = "SELECT `username` FROM `users` WHERE `userid` = '" + authorid + "'";
			ResultSet rs3 = stmt.executeQuery(sql3);
			if(!rs3.first()) {
				return null;
			}
			authorname = rs3.getString(1);
			
			retval = script;
			retval += "#" + ((settingid == null)? "" : settingid);
			retval += "#" + settingname;
			retval += "#" + authorid;
			retval += "#" + authorname;
			retval += "#" + timestamp;
			
			rs1.close(); 
			rs3.close();
			stmt.close();
			con.close();
			
		} catch(Throwable t) {
			Host.out(Values.ErrorCode.D008badgetscript + "\nDetails: caught " + t.getClass() + "\nmsg: \"" + t.getMessage() + "\"");
			t.printStackTrace();
		} 
		
		return retval;
	}

	static boolean isSessionValid(String userId, String jSessionId) {
		
		if(userId == null && jSessionId == null) return true;
		if(userId.toUpperCase().equals("NULL") && jSessionId.toUpperCase().equals("NULL")) return true;
		
		// TODO 2 isSessionValid
		
		return true;
	}
	
	static Vector<String[]> getClientList() {
		Vector<String[]> retobj = new Vector<String[]>();
		
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			
			String sql1 = "SELECT `ip`, `port` FROM `clients`";
			
			ResultSet rs1 = stmt.executeQuery(sql1);
			
			if(rs1.first()) { 
				do {
					String[] line = new String[2];
					line[0] = rs1.getString(1);
					line[1] = rs1.getString(2);
					retobj.add(line);
				} while(rs1.next());
			}
			
			rs1.close();
			
			stmt.close();
			con.close();
		} catch(Throwable t) {
			Host.fatal(Values.ErrorCode.D011noclients + " Unable to get database data. Caught " + Host.throwableDump(t));
		} 
		
		return retobj;
	}
	
	public static String removeClient(String ip, Integer port) {
		if(ip != null) {
			ip = ip.trim();
			if(ip.isEmpty()) ip = "127.0.0.1";
		}
		if(port == null) port = Integer.getInteger(Values.CLIENT_DEFAULT_PORT);
		
		String retval = "";
		
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			
			String sql1 = "DELETE FROM `clients` WHERE `ip` = '" + ip + "' AND `port` = '" + port.intValue() + "'";
			
			if(stmt.executeUpdate(sql1) < 0) {
				retval = "No rows updated.";
			}
			
			stmt.close();
			con.close();
		} catch(Throwable t) {
			retval = "Error saving to database. Caught: " + Host.throwableDump(t);
		}
		
		return retval;
	}
	
	public static String setClient(String ip, Integer port) {
		if(ip != null) {
			ip = ip.trim();
			if(ip.isEmpty()) ip = "127.0.0.1";
		}
		if(port == null) port = Integer.getInteger(Values.CLIENT_DEFAULT_PORT);
		
		String retval = "";
		
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			
			String sql1 = "SELECT `id` FROM `clients` WHERE `ip` = '" + ip + "' AND `port` = '" + port + "'";
			
			ResultSet rs1 = stmt.executeQuery(sql1);
			
			if(rs1.first()) {
//				String sql2 = "UPDATE `client` SET `port` = '" + port + "' WHERE `ip` = '" + ip + "'";
//				if(stmt.executeUpdate(sql2) < 1) retval += "No rows updated.";
			} else {
				String sql2 = "INSERT INTO `clients` (`ip`, `port`) VALUES ('" + ip + "', '" + port + "')";
				if(stmt.executeUpdate(sql2) < 1) retval += "No rows updated.";
			}
			
			stmt.close();
			con.close();
		} catch(Throwable t) {
			retval = "Error saving to database. Caught: " + Host.throwableDump(t);
		}
		
		return retval;
	}
	
	/**
	 * Retrieves a list of the internet connections of a computer running an 
	 * instance of {@link DaemonClient}, which in turn produces information by 
	 * running the Linux script:<br><br> {@code netstat -Wn -tu}.<br><br>
	 * The headers of the netstat result are also included, as if the script
	 * was run straight from the command line.
	 * 
	 * @param ip 
	 * the ip address of the computer, assumes the value "{@code 127.0.0.1}" 
	 * if <code>null</code> or an empty string is given
	 *  
	 * @param port 
	 * the port where the {@link DaemonClient} instance listens to, assumes the 
	 * value of {@link AbstractDaemon#CLIENT_DEFAULT_PORT} if <code>null</code>
	 * is given
	 * 
	 * @return 
	 * a {@link Vector} object containing the results of netstat; will have a 
	 * size of 0 on error
	 */
	public static Vector<String> getClientConnections(String ip, Integer port) {
		Vector<String> orderedSet = new Vector<String>();
//		HashSet<String> set = new HashSet<String>(0);
		Socket s = null;
		
		if(ip != null) {
			ip = ip.trim();
			if(ip.isEmpty()) ip = null;
		}
		if(port == null) port = Integer.getInteger(Values.CLIENT_DEFAULT_PORT);
		
		try {
			
			// connect to the socket
			InetAddress inet = InetAddress.getByName(ip);
			s = new Socket(inet, port);
			
			// prepare data streams
			BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
			OutputStream out = s.getOutputStream();
			PrintWriter pw = new PrintWriter(out, true);
			// send a signal to the client that we want to get some data
			pw.println("handshake"); // we like handshakes, yes?
			
			// get the data
			String line = "";
//			line = in.readLine().toLowerCase(); // first line, "Active internet connections . . ."
//			if(!line.contains("active") || !line.contains("internet") || !line.contains("connections"))
//					throw new InvalidObjectException("Unexpected string from remote netstat call");
//			line = in.readLine().toLowerCase(); // second line, "Proto Recv-Q Send-Q . . ."
//			if(!line.contains("local address") || !line.contains("foreign address")) 
//					throw new InvalidObjectException("Unexpected string from remote netstat call");
			while(line != null) { // for each part, add to set
				line = in.readLine();
				if(line == null) continue;
				orderedSet.add(line);
			}
			
		} catch (UnknownHostException uhe) {
			Host.err("cannot find host (" + ip + ":" + port + ")");
//		} catch (InvalidObjectException ioe) { 
//			err("bad client netstat (" + ip + ":" + port + ")");
		} catch (IOException e) {
//			err("caught ioe");
		} catch (Throwable caught) {
			//Host.throwableDump(caught);
			// fatal
		} finally {
			try {
				if(s != null) s.close();
			} catch (IOException e) {
				// fatal
			}
		}
		
		return orderedSet;
	}
	
	public static Vector<String[]> getActionList() {
		Vector<String[]> retobj = new Vector<String[]>();
		
		try {
			Class.forName("org.gjt.mm.mysql.Driver").newInstance();
			
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost/autotc", 
					"root", 
					"password");
			
			con.setAutoCommit(false);
			
			Statement stmt = con.createStatement();
			
			String sql1 = "SELECT `id`, `prio`, `detect`, `action` FROM `actions` ORDER BY `prio` ASC";
			
			ResultSet rs1 = stmt.executeQuery(sql1);
			
			if(rs1.first()) {
				do {
					int columns = 4;
					String[] line = new String[columns];
					for(int i = 0; i < columns; i++) {
						line[i] = rs1.getString(i + 1);
					}
					retobj.add(line);
				} while(rs1.next());
			}
			
			rs1.close();
			
			stmt.close();
			con.close();
		} catch(Throwable t) {
//			out(throwableDump(t));
		} 
		
		return retobj;
	}
	
	public static void test() {
		// getClientConnections
//		String ip = "127.0.0.1";
//		int port = DEFAULT_CLIENT_PORT;
//		out("Running: getClientConnections(" + ip + "," + port + ")");
//		HashSet<String[]> hs = getClientConnections(ip, port);
//		int n = hs.size();
//		out("n = " + n);
//		if(n > 0) {
//			Iterator<String[]> ite = hs.iterator();
//			while(ite.hasNext()) {
//				String[] line = ite.next();
//				for(int i = 0; i < line.length; i++) System.out.print("{" + line[i] + "}");
//				System.out.println();
//			}
//		}
		try {
			System.out.println(Host.getCmd());
		} catch (Throwable caught) {
			caught.printStackTrace();
		}
	}
	
	static void startServer(Integer port) {

		final String WEBAPPDIR = "root/";
		 
		final Server server = new Server(port);
		
		final String CONTEXTPATH = "/autotc";
		 
		final URL warUrl = Loader.class.getClassLoader().getResource(WEBAPPDIR);
		System.out.println("warUrl : " + warUrl);
		final String warUrlString = warUrl.toExternalForm();
		server.setHandler(new WebAppContext(warUrlString, CONTEXTPATH));
		
		try {
			server.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * <code>
	 * JAR -w USERID JSESSIONID FLAGS <br>
	 * FLAGS: <br>
	 * -devicelist <br>
	 * -timestamp <br>
	 * -getscript DEVICE <br>
	 * -setscript DEVICE SETTINGID SCRIPT<br> <!-- AUTHOR, get from userid; TIMESTAMP, get from {@link AbstractDaemon} -->
	 * -gettemplatelist <br>
	 * -settemplate DEVICE TEMPLATENAME SCRIPT <br>
	 * -getclientlist <br>
	 * -setclient IPv4ADDRESS <br>
	 * -checkclient IPv4ADDRESS <br>
	 * -netstat IPv4ADDRESS PORT <br>
	 * -setaction PRIO DETECT ACTION
	 * </code>
	 * @param args
	 * @return
	 */
	static void webappControl(String[] args) {
		
		if(args.length < 4) {
			Host.out(Values.ErrorCode.D001wbadargs);
			for(int i = 0; i < args.length; i++) {
				Host.out(args[i]);
			}
			return;
		}
		
		String userid = args[1];
		String jsessionid = args[2];
		
		if(!isSessionValid(userid, jsessionid)) {
			Host.out(Values.ErrorCode.D002wbadjsessionid);
			return;
		}
		
		if(args[3].equals("-devicelist")) {
			String out = "", ifconfig = "";
			boolean listHasStarted = false;
			
			try {
				ifconfig = Host.exec("ifconfig");
				String[] devices = ifconfig.split("\n\n");
				for(int i = 0; i < devices.length; i++) {
					if(devices[i].contains("LOOPBACK")) continue;
					int space = devices[i].indexOf(' ');
					if(listHasStarted) out += ",";
					else listHasStarted = true;
					out += devices[i].substring(0, space);
				}
			} catch (Throwable t) {
				Host.out(Values.ErrorCode.D004wbadifconfig);
			}
			
			if(out.isEmpty()) {
				Host.out("No configurable devices found.");
			} else {
				Host.out(out);
			}
		} else if(args[3].equals("-timestamp")) {
			Host.out(Host.timeStamp());
		} else if(args[3].equals("-getscript")) {
			if(args.length != 5) Host.fatal(Values.ErrorCode.D001wbadargs);
			String device = args[4];
			String s = getScript(device);
			if(s == null) Host.out("No script found.");
			else Host.out(s);
		} else if(args[3].equals("-setscript")) {
			if(args.length != 7) Host.fatal(Values.ErrorCode.D001wbadargs);
			String device = args[4];
			String settingid = args[5];
			String script = args[6];
			String timestamp = Host.timeStamp();
			Host.out(setScript(device, settingid, userid, timestamp, script));
		} else if(args[3].equals("-gettemplatelist")) {
			if(args.length < 4) Host.fatal(Values.ErrorCode.D001wbadargs);
			String device = null;
			if(args.length == 5) device = args[4];
			Host.out(getTemplateList(device));
		} else if(args[3].equals("-settemplate")) {
			if(args.length != 7) Host.fatal(Values.ErrorCode.D001wbadargs);
			String device = args[4];
			String templatename = args[5];
			String script = args[6];
			Host.out(setTemplate(device, templatename, script));
		} else if(args[3].equals("-netstat")) {
			if(args.length != 6) Host.fatal(Values.ErrorCode.D001wbadargs);
			String ip = args[4];
			Integer port = null;
			try {
				port = new Integer(args[5]);
			} catch (NumberFormatException e) { }
			Vector<String> set = getClientConnections(ip, port);
			if(set.size() == 0) Host.out(Values.ErrorCode.D010badnetstat + " (" + ip + ":" + port + ")");
			Iterator<String> ite = set.iterator();
			while(ite.hasNext()) {
				Host.out(ite.next());
			}
		} else if(args[3].equals("-getclientlist")) {
			Vector<String[]> set =  getClientList();
			if(set.size() == 0) Host.out(Values.ErrorCode.D011noclients);
			Iterator<String[]> ite = set.iterator();
			while(ite.hasNext()) {
				String[] line = ite.next();
				Host.out(line[0] + " " + line[1]);
			}
		} else if(args[3].equals("-setclient")) {
			if(args.length != 6) Host.fatal(Values.ErrorCode.D001wbadargs);
			String ip = args[4];
			Integer port = null;
			try { port = new Integer(args[5]); } catch (Exception e) { }
			Host.out(setClient(ip, port));
		} else if(args[3].equals("-delclient")) {
			if(args.length != 6) Host.fatal(Values.ErrorCode.D001wbadargs);
			String ip = args[4];
			Integer port = null;
			try { port = new Integer(args[5]); } catch (Exception e) { }
			Host.out(removeClient(ip, port));
		} else if(args[3].equals("-getactionlist")) {
			Vector<String[]> set =  getActionList();
			if(set.size() == 0) Host.out(Values.ErrorCode.D012noactions);
			Iterator<String[]> ite = set.iterator();
			while(ite.hasNext()) {
				String[] line = ite.next();
				String s = "";
				for(int i = 0; i < line.length; i++) {
					if(i != 0) s += "#";
					s += line[i];
				}
				Host.out(s);
			}
		} else if(args[3].equals("-setaction")) {
			if(args.length != 7) {
				String msg = "";
				for (int i = 0; i < args.length; i++) {
					msg += "{" + args[i] + "}";
				}
				Host.fatal(Values.ErrorCode.D001wbadargs + msg);
			}
			String prio = args[4];
			String detect = args[5];
			String action = args[6];
			Host.out(setAction(prio, detect, action));
		} else if(args[3].equals("-delaction")) {
			if(args.length != 5) Host.fatal(Values.ErrorCode.D001wbadargs);
			String actionid = args[4];
			Host.out(removeAction(actionid));
		} else {
			Host.out(Values.ErrorCode.D001wbadargs);
		}
	}

	/**
	 * <code>
	 * JAR -u FLAGS <br>
	 * FLAGS: <br>
	 * -in USERNAME PASSWORD JSESSIONID <br>
	 * -out USERNAME JSESSIONID <br>
	 * </code>
	 * @param args
	 */
	static void userControl(String[] args) {
		if(args.length < 3) {
			Host.out(Values.ErrorCode.D003ubadargs);
		}
		
		if(args[1].equals("-in")) {
			try {
				String username = args[2];
				String password = args[3];
				String jsessionid = args[4];
				
				Database d = new Database(dbhost, dbport, dbuser, dbpass);
				String userid = d.userLogin(username, password, jsessionid);
				
				if(userid != null) {
					Host.out(userid);
				} else {
					Host.out(Values.ErrorCode.D005badlogin);
				}
			} catch (Throwable t) {
				Host.out(Values.ErrorCode.D003ubadargs);
			}
		} else {
			Host.out(Values.ErrorCode.D003ubadargs);
		}
	}
}
 